import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GamePanel extends JPanel
{ 
	private IBoard _board;
	
	/**
	 * The coordinates of the upper-left square.
	 * Any other square's coordinates should be inferrable from that one, 
	 * given that there is no padding between squares.
	 */
	private Rectangle _firstSquare;
	
	private Color _border;
	
	private Color _dropIndicator;
	private int _dropRow, _dropCol;
	private Font _boldFont;
	private Font _normalFont;

    private IGui _gui;
	
	public GamePanel()
	{
		_gui = new GameGUI();
		
		// STUB
		_border = Color.GRAY;
		_boldFont = new Font("Centrury", Font.BOLD, 14);
		_normalFont = new Font("Centrury", 0, 14);
		
		// Add a listener that can begin a new game when the current game is over.
		_gui.addListener(new PlayAgain());
	}
	
	public void paint(Graphics g)
    {
		int rows = _board.getRowCount();
		int cols = _board.getColCount();
		
		Rectangle rect = getBounds();
		
		// We're double-buffered, so go ahead and wipe the entire background
		// every time.
		g.setColor(_border);
		g.fillRect(0, 0, rect.width, rect.height);
		
		g.setFont(_boldFont);

		// Calculate the biggest square that can be used to draw all the Squares.
		// Use at least half the size of a square for a margin on all four sides.
		// TODO: subtract out vertical space for whose turn it is.
		int rowHeight = rect.height / (rows + 1);
		int colWidth = rect.width / (cols + 1);
		int squareSize = Math.min(rowHeight, colWidth);
		
		// Cache the coordinates of the first square, for later use.
		_firstSquare = new Rectangle(squareSize / 2, squareSize * 3/4, squareSize, squareSize);

		// Display whose turn it is (or if the game is over).
		String gameScore = _board.getGameScore();
		String matchScore = _board.getTournamentScore();
		String playerScore = _board.getCurrentPlayerScore();
		Color color = _board.getCurrentPlayerColor();
//		assert (color != null || playerScore == null);
		
		if (playerScore != null)
		{
			g.setColor(color);
			g.drawString(playerScore, squareSize/4, squareSize/4);
		}

		g.setColor(Color.BLUE);
		if (gameScore != null)
			g.drawString(gameScore, squareSize/4, squareSize/4);
		if (matchScore != null)
		{
			g.setFont(_normalFont);
			g.drawString(matchScore, squareSize/4, squareSize/2);
			g.setFont(_boldFont);
		}
		
		// Draw the matrix, painting unclaimed squares green.  Claimed squares 
		// are painted the color associated with that player.
		Rectangle sqr = new Rectangle(_firstSquare);

if (false)	// New (pretty) way to draw
{		
		Point lastMove = _board.lastMove();
		for (int r = 0; r < rows; r++)
		{
			// Move back to left margin
			sqr.x = colWidth / 2;
			
			for (int c = 0; c < cols; c++)
			{
				g.setColor(_board.getBoardColor());
				boolean thisIsLastMove = lastMove != null 
					&& lastMove.x == c && lastMove.y == r;
				g.fill3DRect(sqr.x, sqr.y, sqr.width, sqr.height, !thisIsLastMove);

				Color p = _board.playerAt(r, c);
				if (p != null)
				{
					g.setColor(p);
					g.fillOval(sqr.x+2, sqr.y+2, sqr.width-4, sqr.height-4);
				}
				
				sqr.x += sqr.width;
			}

			sqr.y += sqr.height;
		}
}
else	// Old (cheap) way to draw.
{
		for (int r = 0; r < rows; r++)
		{
			// Move back to left margin
			sqr.x = colWidth / 2;
			
			for (int c = 0; c < cols; c++)
			{
				Color p = _board.playerAt(r, c);
				if (p == null)
					g.setColor(_board.getBoardColor());
				else
					g.setColor(p);
				g.fill3DRect(sqr.x, sqr.y, sqr.width, sqr.height, true);
				
				sqr.x += sqr.width;
			}

			sqr.y += sqr.height;
		}
		
		Point lastMove = _board.lastMove();
		if (lastMove != null)
		{
			// Draw the last move as sunken (instead of raised like the others).
			sqr = _gui.getSquare(lastMove.y, lastMove.x);
			g.setColor(_board.playerAt(lastMove.y, lastMove.x));
//			g.fill3DRect(sqr.x+1, sqr.y+1, sqr.width-2, sqr.height-2, false);
			g.fill3DRect(sqr.x, sqr.y, sqr.width, sqr.height, false);
		}
}

		// Draw a drop indicator if one has been requested.
		if (_dropIndicator != null)
		{
			sqr = _gui.getSquare(_dropRow, _dropCol);
			if (sqr != null)
			{
				for (int i = 1; i <= 4; i++)
				{
					int inset = i * sqr.width / 9;
					g.setColor(_dropIndicator);
					g.drawOval(sqr.x + inset, sqr.y + inset, 
						sqr.width - 2 * inset, sqr.height - 2 * inset);
				}
			}
		}
		
		// Draw a Pass button below the board.
		// Or if the game is over, draw a play-again button.
		sqr = _gui.getSquare(_board.getRowCount() - 1, _board.getColCount() / 2);
		sqr.y += sqr.height * 3 / 2;
		if (_dropRow == _board.getRowCount())
			g.setColor(Color.YELLOW);
		else
			g.setColor(Color.ORANGE);
		if (!_board.isGameOver())
			g.drawString("PASS", sqr.x, rect.height - 2);
		else
			g.drawString("PLAY AGAIN", sqr.x, rect.height - 2);
	}
	
	
	
	public class GameGUI extends IGui
	{
		public void addListener(Object listener)
		{
			if (listener instanceof MouseListener)
				GamePanel.this.addMouseListener((MouseListener)listener);
			if (listener instanceof MouseMotionListener)
				GamePanel.this.addMouseMotionListener((MouseMotionListener)listener);
			if (listener instanceof KeyListener)
				GamePanel.this.addKeyListener((KeyListener)listener);
		}
		
		public void removeListener(Object listener)
		{
			if (listener instanceof MouseListener)
				GamePanel.this.removeMouseListener((MouseListener)listener);
			if (listener instanceof MouseMotionListener)
				GamePanel.this.removeMouseMotionListener((MouseMotionListener)listener);
			if (listener instanceof KeyListener)
				GamePanel.this.removeKeyListener((KeyListener)listener);
		}
	
		public void setBoard(IBoard board)
		{
			_board = board;
		}

		public Point getSquare(Point pt)
		{
			int col = (pt.x - _firstSquare.x) / _firstSquare.width;
			int row = (pt.y - _firstSquare.y) / _firstSquare.height;
			if (col < 0 || row < 0 || col >= _board.getColCount() || row >= _board.getRowCount())
				return null;
			return new Point(col, row);
		}
		
		public boolean isPassButton(Point pt)
		{
			int col = (pt.x - _firstSquare.x) / _firstSquare.width;
			int row = (pt.y - _firstSquare.y) / _firstSquare.height;
			// The pass button is in the middle below the last row.
			return (col >= _board.getColCount() / 4 
				&& col < _board.getColCount() * 3 / 4 
				&& row == _board.getRowCount());
		}
		
		public Rectangle getSquare(int row, int col)
		{
			if (col < 0 || row < 0 || col >= _board.getColCount() || row >= _board.getRowCount())
				throw new IllegalArgumentException();

			// Simply move a copy of the first rectangle over and down as necessary.
			// The first rectangle is cached from the last time we painted.
			Rectangle r = new Rectangle(_firstSquare);
			r.x += col * _firstSquare.width;
			r.y += row * _firstSquare.height;

			return r;
		}
		
		public void redrawBoard()
		{
			repaint();
		}

		public void showDropIndicator(Color color, int row, int col)
		{
			if (_dropIndicator != color
				|| row != _dropRow
				|| col != _dropCol)
			{
				_dropIndicator = color;
				_dropRow = row;
				_dropCol = col;
				redrawBoard();
			}
		}
	}
	
	public class PlayAgain extends MouseAdapter implements MouseMotionListener
	{
		public void mouseClicked(MouseEvent e)
		{
			if (!_board.isGameOver())
				return;
			if (!_gui.isPassButton(e.getPoint()))
				return;
			if (SwingUtilities.isLeftMouseButton(e))
				_board.beginGame();
			else
			{
				// Secret trick to start a whole new tournament, with new players.
				Othello.main(null);
			}
		}

		public void mouseDragged(MouseEvent e)
		{
		}
		
		public void mouseMoved(MouseEvent e)
		{
			if (!_board.isGameOver())
				return;
			// Highlight the PLAY AGAIN text if we're hovering over it.
			_gui.showDropIndicator(null, _gui.isPassButton(e.getPoint()) ? _board.getRowCount() : -1, -1);
		}
	}
} 

